#include "Driver_ADC.h"

GPIOConfig adcGPIOConfigList[] = { [ADC_GPIO_INDEX_KEY] = { GPIOC,
                                                            { .pin          = FL_GPIO_PIN_10,
                                                              .mode         = FL_GPIO_MODE_ANALOG,
                                                              .outputType   = FL_GPIO_OUTPUT_PUSHPULL,
                                                              .pull         = FL_DISABLE,
                                                              .remapPin     = FL_DISABLE,
                                                              .analogSwitch = FL_DISABLE } } };

// 全局变量，用于存储ADC采样结果
static uint16_t    adcResult       = 0;
static uint32_t    currentChannel  = 0;
static uint32_t    filteredVoltage = 0;
static const float FILTER_ALPHA    = 0.7; // 滤波系数

/**
 * @brief 初始化ADC
 *
 */
void Driver_ADC_Init(void)
{
    FL_ADC_CommonInitTypeDef adcCommonInit = { 0 };
    FL_ADC_InitTypeDef       adcInit       = { 0 };
    FL_NVIC_ConfigTypeDef    nvicConfig    = { 0 };

    /* 配置引脚为模拟功能 */
    /* ADC ADC_15 引脚 PC10 */
    for (uint8_t i = 0; i < ADC_GPIO_INDEX_MAX; ++i) {
        FL_GPIO_Init(adcGPIOConfigList[i].port, &(adcGPIOConfigList[i].gpioInit));
    }

    /* ADC 时钟设置 */
    adcCommonInit.clockSource     = FL_CMU_ADC_CLK_SOURCE_XTHF;
    adcCommonInit.clockPrescaler  = FL_ADC_CLK_PSC_DIV8;
    adcCommonInit.referenceSource = FL_ADC_REF_SOURCE_VDDA;
    adcCommonInit.bitWidth        = FL_ADC_BIT_WIDTH_12B;
    FL_ADC_CommonInit(&adcCommonInit);

    /* ADC 寄存器设置 */
    adcInit.conversionMode        = FL_ADC_CONV_MODE_SINGLE;                 /* 单次模式 */
    adcInit.autoMode              = FL_ADC_SINGLE_CONV_MODE_AUTO;            /* 自动 */
    adcInit.waitMode              = FL_DISABLE;                              /* 等待 */
    adcInit.overrunMode           = FL_ENABLE;                               /* 覆盖上次数据 */
    adcInit.scanDirection         = FL_ADC_SEQ_SCAN_DIR_FORWARD;             /* 通道正序扫描 */
    adcInit.externalTrigConv      = FL_ADC_TRIGGER_EDGE_NONE;                /* 禁止触发信号 */
    adcInit.triggerSource         = FL_DISABLE;
    adcInit.fastChannelTime       = FL_ADC_FAST_CH_SAMPLING_TIME_32_ADCCLK;  /* 快速通道采样时间 */
    adcInit.lowChannelTime        = FL_ADC_SLOW_CH_SAMPLING_TIME_128_ADCCLK; /* 慢速通道采样时间 */
    adcInit.oversamplingMode      = FL_ENABLE;                               /* 过采样打开 */
    adcInit.overSampingMultiplier = FL_ADC_OVERSAMPLING_MUL_8X;              /* 8倍过采样 */
    adcInit.oversamplingShift     = FL_ADC_OVERSAMPLING_SHIFT_3B;            /* 数据右移, /8 */

    FL_ADC_Init(ADC, &adcInit);

    /* 配置ADC中断 */
    FL_ADC_EnableIT_EndOfConversion(ADC); /* 使能转换完成中断 */

    /* 配置NVIC */
    nvicConfig.preemptPriority = 2;      /* 设置中断优先级 */
    FL_NVIC_Init(&nvicConfig, ADC_IRQn); /* 初始化NVIC */
}

/**
 * @brief 获取电压值, 使用了一阶低通滤波
 *
 * @param channel 通道号
 * @return uint32_t 真实电压值mV
 */
uint32_t Driver_ADC_GetVoltage(uint32_t channel)
{
    Driver_ADC_StartSample(channel);

    /* 返回滤波后的电压值 */
    return filteredVoltage;
}

/**
 * @brief 启动ADC采样
 *
 * @param channel 通道号
 */
void Driver_ADC_StartSample(uint32_t channel)
{
    currentChannel = channel;

    /* 清除之前的标志 */
    FL_ADC_ClearFlag_EndOfConversion(ADC);

    /* 选择通道 */
    FL_ADC_EnableSequencerChannel(ADC, channel);

    /* 启动ADC */
    FL_ADC_Enable(ADC);

    /* 开始转换 */
    FL_ADC_EnableSWConversion(ADC);
}

/**
 * @brief ADC中断处理函数
 */
void ADC_IRQHandler(void)
{
    /* 检查是否是转换完成中断 */
    if (FL_ADC_IsActiveFlag_EndOfConversion(ADC)) {
        /* 清除中断标志 */
        FL_ADC_ClearFlag_EndOfConversion(ADC);

        /* 读取ADC转换结果 */
        adcResult = FL_ADC_ReadConversionData(ADC);

        /* 计算原始电压值 */
        uint32_t rawVoltage = adcResult * 5000 / 4095;

        /* 一阶低通滤波 */
        filteredVoltage = (uint32_t)(FILTER_ALPHA * rawVoltage + (1 - FILTER_ALPHA) * filteredVoltage);

        /* 关闭ADC */
        FL_ADC_Disable(ADC);

        /* 关闭通道 */
        FL_ADC_DisableSequencerChannel(ADC, currentChannel);
    }
}
